﻿using UnityEngine;
using System.Collections;
using Holoville.HOTween;

/// <summary>
/// 这类是应该贴到一个游戏对象，在场景中实例化游戏的主要入口点
///  This class is the main entry point of the game it should be attached to a gameobject and be instanciate in the scene
///作者：Pondomaniac Games
///  Author : Pondomaniac Games
/// </summary>
public class MainDemo : MonoBehaviour
{

    public GameObject _indicator;//知道所选瓷砖的指标 
    public GameObject[,] _arrayOfShapes;//包含所有游戏瓦片的主数组 
    private GameObject _currentIndicator;//当前指示器替换和销毁每次玩家更改选择时
    private GameObject _FirstObject;//The first object selected
    private GameObject _SecondObject;//The second object selected
    /// <summary>
    /// 列表的瓷砖我们不能看到在游戏中你可以remplace他们统一的督察和选择所有你想要的东西
    /// </summary>
	public GameObject[] _listOfGems;
    /// <summary>
    /// 损坏对象后，将替换为这一个，所以我们将取代他们后，新的
    /// </summary>
    public GameObject _emptyGameobject;
    public GameObject _particleEffect;//我们想要使用的对象在闪烁的恒星的效果 
    public GameObject _particleEffectWhenMatch;//游戏对象的影响当对象匹配 
    public bool _canTransitDiagonally = false;// 指示是否可以对角切换
    public int _scoreIncrement;// 每次找到匹配瓷砖的点增量 
    private int _scoreTotal = 0;//The score 
    private ArrayList _currentParticleEffets = new ArrayList();//该数组将包含所有匹配的粒子，我们将摧毁后 
    public AudioClip MatchSound;// 找到匹配瓷砖时的音响效果
    public int _gridWidth;// 水平格数 
    public int _gridHeight;//垂直网格单元数

    //使用此初始化
    void Start()
    {
        //初始化数组_gridwidth和_gridheight传入参数
        _arrayOfShapes = new GameObject[_gridWidth, _gridHeight];
        //从参数传递的宝石列表中创建宝石
        for (int i = 0; i <= _gridWidth - 1; i++)
        {
            for (int j = 0; j <= _gridHeight - 1; j++)
            {
                var gameObject = GameObject.Instantiate(_listOfGems[Random.Range(0, _listOfGems.Length)] as GameObject, new Vector3(i, j, 0), transform.rotation) as GameObject;
                _arrayOfShapes[i, j] = gameObject;
            }
        }
        //加上明星效应的宝石叫DoShapeEffect
        InvokeRepeating("DoShapeEffect", 1f, 0.21F);

    }

    // Update is called once per frame
    void Update()
    {

        bool shouldTransit = false;
        //检测玩家点击鼠标左键，如果没有动画播放
        if (Input.GetButtonDown("Fire1") && HOTween.GetTweenInfos() == null)
        {
            Destroy(_currentIndicator);
            //3行是让点击对象得到raycasthit2d将帮助我们知道点击对象
            //Ray ray   = Camera.main.ScreenPointToRay (Input.mousePosition);
            RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
            if (hit.transform != null)
            {  //要知道用户是否已经选择了瓷砖或尚未
                if (_FirstObject == null) _FirstObject = hit.transform.gameObject;
                else
                {
                    _SecondObject = hit.transform.gameObject;
                    shouldTransit = true;
                }

                _currentIndicator = GameObject.Instantiate(_indicator, new Vector3(hit.transform.gameObject.transform.position.x, hit.transform.gameObject.transform.position.y, -1), transform.rotation) as GameObject;
                //如果用户选择第二个瓷砖，我们将交换两个瓷砖和动画他们
                if (shouldTransit)
                {
                    //获取2瓦之间的位置
                    var distance = _FirstObject.transform.position - _SecondObject.transform.position;
                    //测试如果2个瓷砖是彼此相邻，否则我们不会交换他们
                    if (Mathf.Abs(distance.x) <= 1 && Mathf.Abs(distance.y) <= 1)
                    {   //如果我们不希望玩家对角交换
                        if (!_canTransitDiagonally)
                        {
                            if (distance.x != 0 && distance.y != 0)
                            {
                                Destroy(_currentIndicator);
                                _FirstObject = null;
                                _SecondObject = null;
                                return;
                            }
                        }
                        //动画过渡
                        DoSwapMotion(_FirstObject.transform, _SecondObject.transform);
                        //数组中的对象交换
                        DoSwapTile(_FirstObject, _SecondObject, ref _arrayOfShapes);
                    }
                    else
                    {
                        _FirstObject = null;
                        _SecondObject = null;
                    }
                    Destroy(_currentIndicator);
                }
            }
        }
        //如果没有动画播放
        if (HOTween.GetTweenInfos() == null)
        {
            var Matches = FindMatch(_arrayOfShapes);
            //如果我们找到一个匹配的瓷砖  If we find a matched tiles
            if (Matches.Count > 0)
            {//Update the score
                _scoreTotal += Matches.Count * _scoreIncrement;

                foreach (GameObject go in Matches)
                {
                    //Playing the matching sound
                    GetComponent<AudioSource>().PlayOneShot(MatchSound);
                    //Creating and destroying the effect of matching
                    var destroyingParticle = GameObject.Instantiate(_particleEffectWhenMatch as GameObject, new Vector3(go.transform.position.x, go.transform.position.y, -2), transform.rotation) as GameObject;
                    Destroy(destroyingParticle, 1f);
                    //Replace the matching tile with an empty one
                    _arrayOfShapes[(int)go.transform.position.x, (int)go.transform.position.y] = GameObject.Instantiate(_emptyGameobject, new Vector3((int)go.transform.position.x, (int)go.transform.position.y, -1), transform.rotation) as GameObject;
                    //Destroy the ancient matching tiles
                    Destroy(go, 0.1f);
                }
                _FirstObject = null;
                _SecondObject = null;
                //移动瓷砖，以取代空的
                DoEmptyDown(ref _arrayOfShapes);
            }
            //如果没有找到匹配的瓷砖在他们的地方
            else if (_FirstObject != null && _SecondObject != null )
            {
                //Animate the tiles
                DoSwapMotion(_FirstObject.transform, _SecondObject.transform);
                //Swap the tiles in the array
                DoSwapTile(_FirstObject, _SecondObject, ref _arrayOfShapes);
                _FirstObject = null;
                _SecondObject = null;
            }
        }
        //Update the score
        (GetComponent(typeof(TextMesh)) as TextMesh).text = _scoreTotal.ToString();
    }

    // 发现3瓦
    private ArrayList FindMatch(GameObject[,] cells)
    {//创建一个数组来存储匹配的瓦片
        ArrayList stack = new ArrayList();
        //检查垂直瓷砖
        //0表示二维数组的第一维，1表示数组的第二维
        //GetUpperBound可以获取数组的最高下标。
        //GetLowerBound可以获取数组的最低下标。
        for (var x = 0; x <= cells.GetUpperBound(0); x++)
        {
            for (var y = 0; y <= cells.GetUpperBound(1); y++)
            {
                var thiscell = cells[x, y];
                //If it's an empty tile continue
                if (thiscell.name == "Empty(Clone)") continue;
                int matchCount = 0;
                int y2 = cells.GetUpperBound(1);
                int y1;
                //Getting the number of tiles of the same kind
                for (y1 = y + 1; y1 <= y2; y1++)
                {
                    if (cells[x, y1].name == "Empty(Clone)" || thiscell.name != cells[x, y1].name) break;
                    matchCount++;
                }
                //If we found more than 2 tiles close we add them in the array of matching tiles
                //如果我们发现2多个瓷砖关闭，我们将它们添加在阵列的匹配瓷砖
                if (matchCount >= 2)
                {
                    y1 = Mathf.Min(cells.GetUpperBound(1), y1 - 1);
                    for (var y3 = y; y3 <= y1; y3++)
                    {
                        if (!stack.Contains(cells[x, y3]))
                        {
                            stack.Add(cells[x, y3]);
                        }
                    }
                }
            }
        }
        //Checking the horizontal tiles , in the following loops we will use the same concept as the previous ones
        //检查水平瓷砖，在下面的循环中，我们将使用以前的相同的概念
        for (var y = 0; y < cells.GetUpperBound(1) + 1; y++)
        {
            for (var x = 0; x < cells.GetUpperBound(0) + 1; x++)
            {
                var thiscell = cells[x, y];
                if (thiscell.name == "Empty(Clone)") continue;
                int matchCount = 0;
                int x2 = cells.GetUpperBound(0);
                int x1;
                for (x1 = x + 1; x1 <= x2; x1++)
                {
                    if (cells[x1, y].name == "Empty(Clone)" || thiscell.name != cells[x1, y].name) break;
                    matchCount++;
                }
                if (matchCount >= 2)
                {
                    x1 = Mathf.Min(cells.GetUpperBound(0), x1 - 1);
                    for (var x3 = x; x3 <= x1; x3++)
                    {
                        if (!stack.Contains(cells[x3, y]))
                        {
                            stack.Add(cells[x3, y]);
                        }
                    }
                }
            }
        }
        return stack;
    }

    // Swap Motion Animation, to animate the switching arrays
    //交换运动动画，动画的开关阵列
    void DoSwapMotion(Transform a, Transform b)
    {
        Vector3 posA = a.localPosition;
        Vector3 posB = b.localPosition;
        //坐标 ,加速类型
        TweenParms parms = new TweenParms().Prop("localPosition", posB).Ease(EaseType.EaseOutQuart);
        HOTween.To(a, 0.25f, parms).WaitForCompletion();
        parms = new TweenParms().Prop("localPosition", posA).Ease(EaseType.EaseOutQuart);
        HOTween.To(b, 0.25f, parms).WaitForCompletion();
    }


    // Swap Two Tile, it swaps the position of two objects in the grid array
    //交换两个瓦片，在网格数组中交换两个对象的位置
    void DoSwapTile(GameObject a, GameObject b, ref GameObject[,] cells)
    {
        GameObject cell = cells[(int)a.transform.position.x, (int)a.transform.position.y];
        cells[(int)a.transform.position.x, (int)a.transform.position.y] = cells[(int)b.transform.position.x, (int)b.transform.position.y];
        cells[(int)b.transform.position.x, (int)b.transform.position.y] = cell;
    }

    // 做空瓦下移
    private void DoEmptyDown(ref GameObject[,] cells)
    {   //用上面的空瓦片替换
        for (int x = 0; x <= cells.GetUpperBound(0); x++)
        {
            for (int y = 0; y <= cells.GetUpperBound(1); y++)
            {
                var thisCell = cells[x, y];
                if (thisCell.name == "Empty(Clone)")
                {
                    for (int y2 = y; y2 <= cells.GetUpperBound(1); y2++)
                    {
                        if (cells[x, y2].name != "Empty(Clone)")
                        {
                            cells[x, y] = cells[x, y2];
                            cells[x, y2] = thisCell;
                            break;
                        }
                    }
                }
            }
        }
        //Instantiate new tiles to replace the ones destroyed
        //实例化新的瓦片取代破坏
        for (int x = 0; x <= cells.GetUpperBound(0); x++)
        {
            for (int y = 0; y <= cells.GetUpperBound(1); y++)
            {
                if (cells[x, y].name == "Empty(Clone)")
                {
                    Destroy(cells[x, y]);
                    cells[x, y] = GameObject.Instantiate(_listOfGems[Random.Range(0, _listOfGems.Length)] as GameObject, new Vector3(x, cells.GetUpperBound(1) + 2, 0), transform.rotation) as GameObject;

                }
            }
        }

        for (int x = 0; x <= cells.GetUpperBound(0); x++)
        {
            for (int y = 0; y <= cells.GetUpperBound(1); y++)
            {

                TweenParms parms = new TweenParms().Prop("position", new Vector3(x, y, -1)).Ease(EaseType.EaseOutQuart);
                HOTween.To(cells[x, y].transform, .4f, parms);
            }
        }
    }
    //Instantiate the star objects
    void DoShapeEffect()
    {
        foreach (GameObject row in _currentParticleEffets)
            Destroy(row);
        for (int i = 0; i <= 2; i++)
            _currentParticleEffets.Add(GameObject.Instantiate(_particleEffect, new Vector3(Random.Range(0, _arrayOfShapes.GetUpperBound(0) + 1), Random.Range(0, _arrayOfShapes.GetUpperBound(1) + 1), -1), new Quaternion(0, 0, Random.Range(0, 1000f), 100)) as GameObject);
    }


}
